package posecco.client;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import posecco.shared.*;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Registration extends FlowPanel {

	/**
	 * Create a remote service proxy to talk to the server-side Greeting service.
	 */
	private final RegistrationServiceAsync registrationService = GWT.create(RegistrationService.class);
	private final LoginServiceAsync loginService = GWT.create(LoginService.class);

	final FieldUtil fieldUtil = new FieldUtil();
	private Boolean isUpdate = true;

	public Registration() {
		this(null);
		isUpdate = false;
	}
	
	private long id;
	
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public Registration(Long id) {
		
		// Button sendButton = new Button("Send");
		if (id != null) {
			
			this.id = id;
		}
		fieldUtil.addFormTextField(this, "login");
		fieldUtil.addFormPwdField(this, "pwd");
		fieldUtil.addFormPwdField(this, "pwdConf");
		fieldUtil.addFormTextField(this, "firstName");
		fieldUtil.addFormTextField(this, "lastName");
		fieldUtil.addFormTextField(this, "email");
		fieldUtil.addRoleSelectionField(this, "role");
		final Button sendButton = new Button("Send");;
		add(sendButton);
		
		// Create the popup dialog box
		final DialogBox dialogBox = new DialogBox();
		dialogBox.setText("Remote Procedure Call");
		dialogBox.setAnimationEnabled(true);
		final Button closeButton = new Button(Util.getMessage("closeButtonLabel"));
		// We can set the id of a widget by accessing its Element
		closeButton.getElement().setId("closeButton");
		final Label textToServerLabel = new Label();
		final HTML serverResponseLabel = new HTML();
		VerticalPanel dialogVPanel = new VerticalPanel();
		dialogVPanel.addStyleName("dialogVPanel");
		dialogVPanel.add(new HTML("<b>" + Util.getMessage("createUserInfo") + ":</b>"));
		dialogVPanel.add(textToServerLabel);
		dialogVPanel.add(new HTML("<br><b>" + Util.getMessage("serverReply") + ":</b>"));
		dialogVPanel.add(serverResponseLabel);
		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
		dialogVPanel.add(closeButton);
		dialogBox.setWidget(dialogVPanel);

		
		// Add a handler to close the DialogBox
		closeButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
				sendButton.setEnabled(true);
				sendButton.setFocus(true);
			}
		});

		// Create a handler for the sendButton and nameField
		class MyHandler implements ClickHandler, KeyUpHandler {
			/**
			 * Fired when the user clicks on the sendButton.
			 */

			public void onClick(ClickEvent event) {
				sendDataToServer();
			}
			
			public void onKeyUp(KeyUpEvent event) {
				
				validateFields(((TextBox)event.getSource()).getName());
			}
			
			private int validateFields(String fieldName) {
				
				String login = fieldUtil.getFieldValue("login");
				String pwd = fieldUtil.getFieldValue("pwd");
				String pwdConf = fieldUtil.getFieldValue("pwdConf");
				String firstName = fieldUtil.getFieldValue("firstName");
				String lastName = fieldUtil.getFieldValue("lastName");
				String email = fieldUtil.getFieldValue("email");
				
				if (fieldName.equals("all")) {
					
					Iterator<Entry<String, Object>> it = fieldUtil.getFields().entrySet().iterator();
				    while (it.hasNext()) {
				        Map.Entry<String, Object> pairs = (Map.Entry<String, Object>)it.next();
				        fieldUtil.setErrorMessage(pairs.getKey(), "");
				    }					
				}
				else {
					
					fieldUtil.setErrorMessage(fieldName, "");
				}
				int errorCount = 0;
				if (fieldName.equals("all") || fieldName.equals("login")) {
					
					if (FieldVerifier.isEmpty(login)) {
						
						fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorEmpty"));					
						errorCount++;
					}		
					if (!FieldVerifier.isValidLogin(login)) {
						fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorLength"));
						errorCount++;
					}
					registrationService.loginTaken(getId(), login, new AsyncCallback<Boolean>() {
						public void onFailure(Throwable caught) {}
		
						public void onSuccess(Boolean result) {
							try {	
								if (result) {
									fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorTaken"));
								}
							}
							catch (NullPointerException e) {}
						}
					});
				}
				// Beim Update wird das Passwort nicht gespeichert, daher auch nicht validiert
				if (!isUpdate) {
					if (fieldName.equals("all") || fieldName.equals("pwd")) {
						
						if (FieldVerifier.isEmpty(pwd)) {
							
							fieldUtil.setErrorMessage("pwd", Util.getMessage("pwdErrorEmpty"));					
							errorCount++;
						}
						if (!FieldVerifier.isValidPassword(pwd, pwdConf)) {
							fieldUtil.setErrorMessage("pwdConf", Util.getMessage("pwdErrorMatch"));
							errorCount++;
						}
					}
					if (fieldName.equals("all") || fieldName.equals("pwdConf")) {
						
						if (FieldVerifier.isEmpty(pwdConf)) {
							
							fieldUtil.setErrorMessage("pwdConf", Util.getMessage("pwdConfErrorEmpty"));					
							errorCount++;
						}
						if (!FieldVerifier.isValidPassword(pwd, pwdConf)) {
							fieldUtil.setErrorMessage("pwdConf", Util.getMessage("pwdErrorMatch"));
							errorCount++;
						}
					}
				}
				if (fieldName.equals("all") || fieldName.equals("firstName")) {
					
					if (FieldVerifier.isEmpty(firstName)) {
						
						fieldUtil.setErrorMessage("firstName", Util.getMessage("firstNameErrorEmpty"));					
						errorCount++;
					}
				}
				if (fieldName.equals("all") || fieldName.equals("lastName")) {
					
					if (FieldVerifier.isEmpty(lastName)) {
						
						fieldUtil.setErrorMessage("lastName", Util.getMessage("lastNameErrorEmpty"));					
						errorCount++;
					}					
				}
				if (fieldName.equals("all") || fieldName.equals("email")) {
					
					if (FieldVerifier.isEmpty(email)) {
						
						fieldUtil.setErrorMessage("email", Util.getMessage("emailErrorEmpty"));					
						errorCount++;
					}
					if (!FieldVerifier.isValidEMail(email)) {
						
						fieldUtil.setErrorMessage("email", Util.getMessage("emailErrorInvalid"));					
						errorCount++;
					}
				}
				return errorCount;
			}


			/**
			 * Send the name from the nameField to the server and wait for a response.
			 */
			private void sendDataToServer() {
				
				final String login = fieldUtil.getFieldValue("login");
				final String pwd = Util.getHash(fieldUtil.getFieldValue("pwd"));
				final String pwdConf = Util.getHash(fieldUtil.getFieldValue("pwdConf"));
				final String firstName = fieldUtil.getFieldValue("firstName");
				final String lastName = fieldUtil.getFieldValue("lastName");
				final String email = fieldUtil.getFieldValue("email");
				fieldUtil.removeErrorMessages();
				if (validateFields("all") == 0) {
					sendButton.setEnabled(false);
					serverResponseLabel.setText("");
					if (isUpdate) {
						
						registrationService.updateUser(getId(), login, email, firstName, lastName, new AsyncCallback<User>() {
							public void onFailure(Throwable caught) {
								// Show the RPC error message to the user
								dialogBox
										.setText(Util.getMessage("remoteCallFailed") + ": " + caught.getMessage());
								serverResponseLabel
										.addStyleName("serverResponseLabelError");
								dialogBox.center();
								closeButton.setFocus(true);
							}
					
							public void onSuccess(User result) {
								try {	
									if (result != null) {
										dialogBox.setText(Util.getMessage("remoteCall"));
										serverResponseLabel
												.removeStyleName("serverResponseLabelError");
										serverResponseLabel.setHTML(Util.getMessage("user") + " " + result.getLogin() + " " + Util.getMessage("createdSuccessfully"));
										Navigation.gotoPage("userList");
										dialogBox.center();
										closeButton.setFocus(true);
									}
									else {
										fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorTaken"));
										sendButton.setEnabled(true);
									}
								}
								catch (NullPointerException e) {							
									fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorTaken"));
									sendButton.setEnabled(true);
								}
							}
						});
					}
					else {
						
						registrationService.addUser(login, pwd, pwdConf, email, firstName, lastName, new AsyncCallback<User>() {
							public void onFailure(Throwable caught) {
								// Show the RPC error message to the user
								dialogBox
										.setText(Util.getMessage("remoteCallFailed") + ": " + caught.getMessage());
								serverResponseLabel
										.addStyleName("serverResponseLabelError");
								dialogBox.center();
								closeButton.setFocus(true);
							}
					
							public void onSuccess(User result) {
								try {	
									if (result != null) {
										dialogBox.setText(Util.getMessage("remoteCall"));
										serverResponseLabel
												.removeStyleName("serverResponseLabelError");
										serverResponseLabel.setHTML(Util.getMessage("user") + " " + result.getLogin() + " " + Util.getMessage("createdSuccessfully"));
										dialogBox.center();
										Navigation.gotoPage("login");
										closeButton.setFocus(true);
									}
									else {
										fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorTaken"));
										sendButton.setEnabled(true);
									}
								}
								catch (NullPointerException e) {							
									fieldUtil.setErrorMessage("login", Util.getMessage("loginErrorTaken"));
									sendButton.setEnabled(true);
								}
							}
						});
					}
				}
			}
		}


		// Add a handler to send the name to the server
		MyHandler handler = new MyHandler();
		sendButton.addClickHandler(handler);
		Iterator<Entry<String, Object>> it = fieldUtil.getFields().entrySet().iterator();
	    while (it.hasNext()) {
	        Map.Entry<String, Object> pairs = (Map.Entry<String, Object>)it.next();
	        if (((FieldRow) pairs.getValue()).getType().indexOf("Select") == -1) { 
	        	((TextBox) ((FieldRow) pairs.getValue()).getField()).addKeyUpHandler(handler);
	        }
	    }
	    if (id != null) {
			loginService.getUserById(id, new AsyncCallback<User>() {
				public void onFailure(Throwable caught) {}
		
				public void onSuccess(User result) {
					
					fieldUtil.setFieldValues(result);
				}
			});
	    }
	}
	

}
